/////////////////////////////////////////////////////////////////////////////////////////////
// Filename: D3DClass.cpp
// (c) Dave Ottley, 2012. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////
//		INCLUDES
///////////////////////////
#include <Windows.h>
#include <iostream>
#include <fstream>
#include <assert.h>
#include <vector>
#include <memory>
#include <d3dcompiler.h>
#include <d3d11.h>
#include <D3DX11.h>

///////////////////////////
//		MY INCLUDES
///////////////////////////
#include "Constants.h"
#include "ApplicationLayer.h"
#include "D3DClass.h"
#include "Util.h"
#include "WICTextureLoader.h"
#include "SubsystemID.h"
#include "Messages.h"
#include "GraphicsOwnedStates.h"
#include "Rect.h"
#include "SubsystemID.h"
#include "Telegram.h"

#pragma comment(lib, "dxgi.lib")
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "d3dx11.lib")
#pragma comment(lib, "dxerr.lib")
#pragma comment(lib, "d3dcompiler.lib")
#pragma comment( lib, "dxguid.lib")

/////////////////////////////////////////////////////////////////////////////////////////////
// 
//						CONSTRUCTOR / GET INSTANCE
//
/////////////////////////////////////////////////////////////////////////////////////////////
D3DClass::D3DClass()
	:
	mDevice(0),
	mContext(0),
	mSwapChain(0),
	mRenderTargetView(0),
	mDepthStencilView(0),
	mDepthStencilBuffer(0),
	mDepthEnabledStencilState(0),
	mDepthDisabledStencilState(0),
	mRasterizerState(0),
	mVRam(0),
	mRefreshNumerator(0),
	mRefreshDenominator(0),
	mPixelShader(0),
	mVertexShader(0),
	mSamplerLinear(0),
	mVertexLayout(0),
	mVSBlob(0),
	mPSBlob(0),
	mDebug(0),
	mBackBuffer(0),
	mCurrentMasterAtlas(0),
	mVSync(VSYNC),
	mFullscreen(FULL_SCREEN),
	mNearPlane(NEAR_PLANE),
	mFarPlane(FAR_PLANE),
	mFeatureLevel(D3D_FEATURE_LEVEL_9_1),
	mDriverType(D3D_DRIVER_TYPE_NULL),
	mStateMachine(new StateMachine<D3DClass>(this)),
	mStockIndexBuffer(0),
	mID(SubsystemID::GRAPHICS),
	 mAtlasWidth(0), 
	 mAtlasHeight(0),
	 mIndexedAtlasedSpriteCounter(0)
{

	mNonAtlasedSpriteResources.reserve(MAX_NONATLASED_SPRITES);
	mAtlasedVertexBuffer.reserve(MAX_ATLASED_SPRITES * QUAD_VERTEX_COUNT);
	mAtlasedIndexBuffer.reserve(MAX_ATLASED_SPRITES * QUAD_INDEX_COUNT);

	CreateQuadIndexBuffer(&mStockIndexBuffer);

	// Setup the State Machine	
	mStateMachine->SetCurrentState( GraphicsNormalState::GetInstance() );
	mStateMachine->SetGlobalState( GraphicsGlobalState::GetInstance() );
	
	ZeroMemory(mDriverTypeName, 200);
	ZeroMemory(mFeatureLevelName, 200);
	
	for(int i = 0; i < 256; ++i)
	{
		mVideoCardDescription[i] = 0;
	}
	XMVECTOR up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f);

	mCameraPos = XMFLOAT4(0.0f, 0.0f, -10.0f, 1.0f);
	mCameraTarget = XMFLOAT4(0.0f, 0.0f, 1.0f, 1.0f);

	XMMATRIX I = XMMatrixIdentity();
	XMStoreFloat4x4(&mIWorld, I);

	// Resize the swap chain and recreate the render target view.
	int screenDimensions[2] = { -1, -1 };
	Telegram telegram(0.0, mID, 0, Request::ScreenDimensions, screenDimensions);
	assert( g_pApp->HandleMessage(telegram) && "<WindowsMsg::RequestScreenDimensions> Unable to retrieve screen dimensions.");
	assert( (screenDimensions[0] != -1 && screenDimensions[1] != -1) && "<WindowsMsg::RequestScreenDimensions> Screen dimensions remain uninitialized");
	int screenWidth = screenDimensions[0];
	int screenHeight = screenDimensions[1];

	XMMATRIX O = XMMatrixOrthographicLH((float) screenWidth, (float)screenHeight, mNearPlane, mFarPlane);
	XMStoreFloat4x4(&mOrtho, O);

	XMMATRIX P = XMMatrixPerspectiveFovLH(FOV_ANGLE, GetAspectRatio(), mNearPlane, mFarPlane);
	XMStoreFloat4x4(&mProj, P);

	XMMATRIX V = XMMatrixLookAtLH(XMLoadFloat4(&mCameraPos), XMLoadFloat4(&mCameraTarget), up);
	XMStoreFloat4x4(&mView, V);
	
}



D3DClass * D3DClass::GetInstance()
{
	static D3DClass theOne;

	return &theOne;
}



/////////////////////////////////////////////////////////////////////////////////////////////
// 
//						DESTRUCTOR / SHUTDOWN
//
/////////////////////////////////////////////////////////////////////////////////////////////
D3DClass::~D3DClass()
{
	delete mStateMachine;
	
}

void D3DClass::Shutdown()
{
	HRESULT hr = 0;

	//Disable full screen before shutting down.
	mSwapChain->SetFullscreenState(FALSE, NULL);

	//Release all COM objects
	ReleaseCOM(mCurrentMasterAtlas);
	ReleaseCOM(mVertexLayout);
	ReleaseCOM(mVertexShader);
	ReleaseCOM(mPixelShader);
	ReleaseCOM(mVSBlob);
	ReleaseCOM(mPSBlob);
	ReleaseCOM(mSamplerLinear);
	ReleaseCOM(mRasterizerState);
	ReleaseCOM(mDepthDisabledStencilState);
	ReleaseCOM(mDepthEnabledStencilState);
	ReleaseCOM(mDepthStencilBuffer);
	ReleaseCOM(mDepthStencilView);
	ReleaseCOM(mBackBuffer);
	ReleaseCOM(mRenderTargetView);
	ReleaseCOM(mSwapChain);
	ReleaseCOM(mDebug);
	ReleaseCOM(mContext);
	ReleaseCOM(mDevice);
	

	
}


/////////////////////////////////////////////////////////////////////////////////////////////
// 
//						INITIALIZE
//
/////////////////////////////////////////////////////////////////////////////////////////////
bool D3DClass::Initialize()
{
	if(!QueryVideoCardInfo())
		return false;

	if(!CreateDeviceAndSwapChain())
		return false;

	if(!LoadCompiledShadersFromFile() )
		return false;

	if(!CreateRenderTargetView())
		return false;

	if(!CreateDepthStencilView())
		return true;

	if(!SetRasterizerState())
		return false;

	if(!CreateSamplerState())
		return false;

	PlayerCount numPlayers;
	Telegram telegram(0.0, mID, 0, Request::NumPlayers, &numPlayers);
	assert( g_pApp->HandleMessage(telegram) && "<ApplicationMsg::RequestNumPlayers> Unable to return number of players.");
	SetViewport(numPlayers);

	return true;
}

/////////////////////////////////////////////////////////////////////////////////////////////
// 
//						ON RESIZE
//
/////////////////////////////////////////////////////////////////////////////////////////////
void D3DClass::OnResize()
{
	assert(mDevice);
	assert(mContext);
	assert(mSwapChain);

	// Release the old views, as they hold references to the buffers we
	// will be destroying.  Also release the old depth/stencil buffer.

	ReleaseCOM(mBackBuffer);
	ReleaseCOM(mRenderTargetView);
	ReleaseCOM(mDepthStencilView);
	ReleaseCOM(mDepthStencilBuffer);



	// Resize the swap chain and recreate the render target view.
	int screenDimensions[2] = { -1, -1 };
	Telegram telegram(0.0, mID, 0, Request::ScreenDimensions, screenDimensions);
	assert (g_pApp->HandleMessage(telegram) && "<WindowsMsg::RequestScreenDimensions> Unable to retrieve screen dimensions.");
	assert( (screenDimensions[0] != -1 && screenDimensions[1] != -1) && "<WindowsMsg::RequestScreenDimensions> Screen dimensions remain uninitialized");
	int screenWidth = screenDimensions[0];
	int screenHeight = screenDimensions[1];

	HR(mSwapChain->ResizeBuffers(1, screenWidth, screenHeight, DXGI_FORMAT_R8G8B8A8_UNORM, 0));
	HR(mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&mBackBuffer)));
	HR(mDevice->CreateRenderTargetView(mBackBuffer, 0, &mRenderTargetView));

	// Create the depth/stencil buffer and view.
	D3D11_TEXTURE2D_DESC depthStencilDesc;
	
	depthStencilDesc.Width     = screenWidth;
	depthStencilDesc.Height    = screenHeight;
	depthStencilDesc.MipLevels = 1;
	depthStencilDesc.ArraySize = 1;
	depthStencilDesc.Format    = DXGI_FORMAT_D24_UNORM_S8_UINT;
	depthStencilDesc.SampleDesc.Count   = 1;
	depthStencilDesc.SampleDesc.Quality = 0;
	depthStencilDesc.Usage          = D3D11_USAGE_DEFAULT;
	depthStencilDesc.BindFlags      = D3D11_BIND_DEPTH_STENCIL;
	depthStencilDesc.CPUAccessFlags = 0; 
	depthStencilDesc.MiscFlags      = 0;

	HR(mDevice->CreateTexture2D(&depthStencilDesc, 0, &mDepthStencilBuffer));	
	HR(mDevice->CreateDepthStencilView(mDepthStencilBuffer, 0, &mDepthStencilView));

	//Set Debug name for the Depth Stencil Buffer
	#ifndef NDEBUG
	const char c_szName[] = "DepthStencilBuffer2";
	mDepthStencilBuffer->SetPrivateData( WKPDID_D3DDebugObjectName, 
	sizeof( c_szName ) - 1, c_szName );
	#endif


	//Set Debug name for the Depth Stencil View
	#ifndef NDEBUG
	const char c_szName2[] = "DepthStencilView2";
	mDepthStencilView->SetPrivateData( WKPDID_D3DDebugObjectName, 
	sizeof( c_szName2 ) - 1, c_szName2 );
	#endif
	
	mContext->OMSetRenderTargets(1, &mRenderTargetView, mDepthStencilView);

	// Set the viewport transform.
	PlayerCount numPlayers;
	telegram = Telegram(0.0, mID, 0, Request::NumPlayers, &numPlayers);
	assert( g_pApp->HandleMessage(telegram) && "<ApplicationMsg::RequestNumPlayers> Unable to return number of players.");
	SetViewport(numPlayers);

	//Because the aspect ratio may have changed, recalculate the projection matrix and ortho matrix
	//which depend on the aspect ratio.
	XMMATRIX P = XMMatrixPerspectiveFovLH(0.25f * XM_PI, GetAspectRatio(), NEAR_PLANE, FAR_PLANE);
	XMStoreFloat4x4(&mProj, P);

	XMMATRIX O = XMMatrixOrthographicLH((float) screenWidth, (float)screenHeight, mNearPlane, mFarPlane);
	XMStoreFloat4x4(&mOrtho, O);
}

/////////////////////////////////////////////////////////////////////////////////////////////
// 
//						QUERRY VIDEO CARD INFO
//
/////////////////////////////////////////////////////////////////////////////////////////////
bool D3DClass::QueryVideoCardInfo()
{
	HRESULT result;
	IDXGIFactory * factory;
	IDXGIAdapter * adapter;
	IDXGIOutput * adapterOutput;
	unsigned int numModes, stringLength;
	DXGI_MODE_DESC * displayModeList;
	DXGI_ADAPTER_DESC adapterDesc;

	int screenDimensions[2] = { -1, -1 };
	Telegram telegram(0.0, mID, 0, Request::ScreenDimensions, screenDimensions);
	assert( g_pApp->HandleMessage(telegram) && "<WindowsMsg::RequestScreenDimensions> Unable to retrieve screen dimensions.");
	assert( (screenDimensions[0] != -1 && screenDimensions[1] != -1) && "<WindowsMsg::RequestScreenDimensions> Screen dimensions remain uninitialized");
	int screenWidth = screenDimensions[0];
	int screenHeight = screenDimensions[1];

	// Create a DirectX graphics interface factory.
	result = CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&factory);
	if(FAILED(result))
	{
		return false;
	}

	// Use the factory to create an adapter for the primary graphics interface (video card).
	result = factory->EnumAdapters(0, &adapter);
	if(FAILED(result))
	{
		return false;
	}

	// Enumerate the primary adapter output (monitor).
	result = adapter->EnumOutputs(0, &adapterOutput);
	if(FAILED(result))
	{
		return false;
	}

	// Get the number of modes that fit the DXGI_FORMAT_R8G8B8A8_UNORM display format for the adapter output (monitor).
	result = adapterOutput->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_ENUM_MODES_INTERLACED, &numModes, NULL);
	if(FAILED(result))
	{
		return false;
	}

	// Create a list to hold all the possible display modes for this monitor/video card combination.
	displayModeList = new DXGI_MODE_DESC[numModes];
	if(!displayModeList)
	{
		return false;
	}

	// Now fill the display mode list structures.
	result = adapterOutput->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_ENUM_MODES_INTERLACED, &numModes, displayModeList);
	if(FAILED(result))
	{
		return false;
	}

	// Now go through all the display modes and find the one that matches the screen width and height.
	// When a match is found store the numerator and denominator of the refresh rate for that monitor.
	for(UINT i=0; i<numModes; i++)
	{
		if(displayModeList[i].Width == (unsigned int)screenWidth )
		{
			if(displayModeList[i].Height == (unsigned int)screenHeight )
			{
				mRefreshNumerator = displayModeList[i].RefreshRate.Numerator;
				mRefreshDenominator = displayModeList[i].RefreshRate.Denominator;
			}
		}
	}

	// Get the adapter (video card) description.
	result = adapter->GetDesc(&adapterDesc);
	if(FAILED(result))
	{
		return false;
	}

	// Store the dedicated video card memory in megabytes.
	mVRam = (int)(adapterDesc.DedicatedVideoMemory / 1024 / 1024);

	// Convert the name of the video card to a character array and store it.
	int error = wcstombs_s(&stringLength, mVideoCardDescription, 128, adapterDesc.Description, 256);
	if(error != 0)
	{
		return false;
	}

	// Release the display mode list.
	delete [] displayModeList;
	displayModeList = 0;

	// Release the adapter output.
	ReleaseCOM(adapterOutput);

	// Release the adapter.
	ReleaseCOM(adapter);

	// Release the factory.
	ReleaseCOM(factory);

	return true;
}

/////////////////////////////////////////////////////////////////////////////////////////////
// 
//						CREATE DEVICE AND SWAP CHAIN
//
/////////////////////////////////////////////////////////////////////////////////////////////
bool D3DClass::CreateDeviceAndSwapChain()
{
	// Variables
	HRESULT result;
	DXGI_SWAP_CHAIN_DESC swapChainDesc;
	UINT createDeviceFlags = 0;
#if defined(DEBUG) || defined(_DEBUG)
	createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
	
	//Obtain screen dimensions from the OS Manager
	int screenDimensions[2] = { -1, -1 };
	Telegram telegram(0.0, mID, 0, Request::ScreenDimensions, screenDimensions);
	assert( g_pApp->HandleMessage(telegram) && "<WindowsMsg::RequestScreenDimensions> Unable to retrieve screen dimensions.");
	assert( (screenDimensions[0] != -1 && screenDimensions[1] != -1) && "<WindowsMsg::RequestScreenDimensions> Screen dimensions remain uninitialized");
	int screenWidth = screenDimensions[0];
	int screenHeight = screenDimensions[1];

	HWND hwnd = 0;
	telegram = Telegram(0.0, mID, 0, Request::WindowHandle, &hwnd);
	assert( g_pApp->HandleMessage(telegram) && "<WindowsMsg::WindowHandle> Unable to obtain window handle.");
	assert( (hwnd != 0 ) && "<WindowsMsg::RequestWindowHandle> Window handle remain uninitialized");


	D3D_FEATURE_LEVEL featureLevels[] = 
	{
		D3D_FEATURE_LEVEL_11_0,		//try first
		D3D_FEATURE_LEVEL_10_1,		//and so on...
		D3D_FEATURE_LEVEL_10_0,
		D3D_FEATURE_LEVEL_9_3,
		D3D_FEATURE_LEVEL_9_2,
		D3D_FEATURE_LEVEL_9_1,
	};
	UINT numFeatureLevels = ARRAYSIZE( featureLevels );
	D3D_DRIVER_TYPE driverTypes[] =
    {
        D3D_DRIVER_TYPE_HARDWARE,	//try first
        D3D_DRIVER_TYPE_WARP,		//and so on...
        D3D_DRIVER_TYPE_REFERENCE,
    };
	UINT numDriverTypes = ARRAYSIZE( driverTypes );

	// Initialize the swap chain description.
    ZeroMemory(&swapChainDesc, sizeof(swapChainDesc));
    swapChainDesc.BufferCount = 1;
	swapChainDesc.BufferDesc.Width = screenWidth;
	swapChainDesc.BufferDesc.Height = screenHeight;
    swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
	if(mVSync)
	{
	    swapChainDesc.BufferDesc.RefreshRate.Numerator = mRefreshNumerator;
		swapChainDesc.BufferDesc.RefreshRate.Denominator = mRefreshDenominator;
	}
	else
	{
	    swapChainDesc.BufferDesc.RefreshRate.Numerator = 0;
		swapChainDesc.BufferDesc.RefreshRate.Denominator = 1;
	}
    swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	swapChainDesc.OutputWindow = hwnd;
    swapChainDesc.SampleDesc.Count = 1;
    swapChainDesc.SampleDesc.Quality = 0;
	swapChainDesc.Windowed = !mFullscreen;
	swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
	swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
	swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
	swapChainDesc.Flags = 0;

	// Create the swap chain, Direct3D device, and Direct3D device context.
	for( UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++ )
    {
        mDriverType = driverTypes[driverTypeIndex];
		result = D3D11CreateDeviceAndSwapChain(	NULL, 
												mDriverType, 
												NULL, 
												createDeviceFlags, 
												featureLevels, 
												numFeatureLevels, 
												D3D11_SDK_VERSION, 
												&swapChainDesc, 
												&mSwapChain, 
												&mDevice, 
												&mFeatureLevel, 
												&mContext);
		if( SUCCEEDED(result))
		{
			switch(driverTypeIndex)
			{
			case 0:
				wcscpy_s(mDriverTypeName, L"Hardware");
				break;
			case 1:
				wcscpy_s(mDriverTypeName, L"WARP");
				break;
			default:
				wcscpy_s(mDriverTypeName, L"Reference");
				break;
			}

			switch(mFeatureLevel)
			{
			case D3D_FEATURE_LEVEL_11_0:
				wcscpy_s(mFeatureLevelName, L"D3D_FEATURE_LEVEL_11_0");
				break;
			case D3D_FEATURE_LEVEL_10_1:
				wcscpy_s(mFeatureLevelName, L"D3D_FEATURE_LEVEL_10_1");
				break;
			case D3D_FEATURE_LEVEL_10_0:
				wcscpy_s(mFeatureLevelName, L"D3D_FEATURE_LEVEL_10_0");
				break;
			case D3D_FEATURE_LEVEL_9_3:
				wcscpy_s(mFeatureLevelName, L"D3D_FEATURE_LEVEL_10_0");
				break;
			case D3D_FEATURE_LEVEL_9_2:
				wcscpy_s(mFeatureLevelName, L"D3D_FEATURE_LEVEL_10_0");
				break;
			case D3D_FEATURE_LEVEL_9_1:
				wcscpy_s(mFeatureLevelName, L"D3D_FEATURE_LEVEL_10_0");
				break;
			default:
				wcscpy_s(mFeatureLevelName, L"Unsupported Feature Level");
				break;
			}

			break; // for loop
		}
	}

	MakeWindowAssociation(); // Disallow default Alt-Enter handling. Handle ourselves

	if(FAILED(result))
	{
		return false;
	}

	mDevice->QueryInterface(__uuidof(ID3D11Debug), (void **) &mDebug);

	return true;
}


/////////////////////////////////////////////////////////////////////////////////////////////
// 
//						CREATE RENDER TARGET VIEW
//
/////////////////////////////////////////////////////////////////////////////////////////////
bool D3DClass::CreateRenderTargetView()
{
	HRESULT result;

	// Get the pointer to the back buffer.
	result = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&mBackBuffer);
	if(FAILED(result))
	{
		return false;
	}

	// Create the render target view with the back buffer pointer.
	result = mDevice->CreateRenderTargetView(mBackBuffer, NULL, &mRenderTargetView);
	if(FAILED(result))
	{
		return false;
	}

	return true;
}

/////////////////////////////////////////////////////////////////////////////////////////////
// 
//						CREATE DEPTH STENCIL VIEW
//
/////////////////////////////////////////////////////////////////////////////////////////////
bool D3DClass::CreateDepthStencilView()
{
	HRESULT result;
	D3D11_TEXTURE2D_DESC depthBufferDesc;
	D3D11_DEPTH_STENCIL_DESC depthStencilDesc;
	D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc;
	D3D11_DEPTH_STENCIL_DESC depthDisabledStencilDesc;

	// Initialize the description of the depth buffer.
	ZeroMemory(&depthBufferDesc, sizeof(depthBufferDesc));

	//Obtain screen dimensions from the OS Manager
	int screenDimensions[2] = { -1, -1 };
	Telegram telegram(0.0, mID, 0, Request::ScreenDimensions, screenDimensions);
	assert( g_pApp->HandleMessage(telegram) && "<WindowsMsg::RequestScreenDimensions> Unable to retrieve screen dimensions.");
	assert( (screenDimensions[0] != -1 && screenDimensions[1] != -1) && "<WindowsMsg::RequestScreenDimensions> Screen dimensions remain uninitialized");
	int screenWidth = screenDimensions[0];
	int screenHeight = screenDimensions[1];

	// Set up the description of the depth buffer.
	depthBufferDesc.Width = screenWidth;
	depthBufferDesc.Height = screenHeight;
	depthBufferDesc.MipLevels = 1;
	depthBufferDesc.ArraySize = 1;
	depthBufferDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
	depthBufferDesc.SampleDesc.Count = 1;
	depthBufferDesc.SampleDesc.Quality = 0;
	depthBufferDesc.Usage = D3D11_USAGE_DEFAULT;
	depthBufferDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
	depthBufferDesc.CPUAccessFlags = 0;
	depthBufferDesc.MiscFlags = 0;

	// Create the texture for the depth buffer using the filled out description.
	result = mDevice->CreateTexture2D(&depthBufferDesc, NULL, &mDepthStencilBuffer);
	if(FAILED(result))
	{
		return false;
	}

	// Initialize the description of the stencil state.
	ZeroMemory(&depthStencilDesc, sizeof(depthStencilDesc));

	// Set up the description of the stencil state.
	depthStencilDesc.DepthEnable = true;
	depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
	depthStencilDesc.DepthFunc = D3D11_COMPARISON_LESS;

	depthStencilDesc.StencilEnable = true;
	depthStencilDesc.StencilReadMask = 0xFF;
	depthStencilDesc.StencilWriteMask = 0xFF;

	// Stencil operations if pixel is front-facing.
	depthStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
	depthStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR;
	depthStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
	depthStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;

	// Stencil operations if pixel is back-facing.
	depthStencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
	depthStencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR;
	depthStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
	depthStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;

	// Create the depth stencil state.
	result = mDevice->CreateDepthStencilState(&depthStencilDesc, &mDepthEnabledStencilState);
	if(FAILED(result))
	{
		return false;
	}
	
	// Clear the second depth stencil state before setting the parameters.
	ZeroMemory(&depthDisabledStencilDesc, sizeof(depthDisabledStencilDesc));

	// Now create a second depth stencil state which turns off the Z buffer for 2D rendering.  The only difference is 
	// that DepthEnable is set to false, all other parameters are the same as the other depth stencil state.
	depthDisabledStencilDesc.DepthEnable = false;
	depthDisabledStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
	depthDisabledStencilDesc.DepthFunc = D3D11_COMPARISON_LESS;
	depthDisabledStencilDesc.StencilEnable = true;
	depthDisabledStencilDesc.StencilReadMask = 0xFF;
	depthDisabledStencilDesc.StencilWriteMask = 0xFF;
	depthDisabledStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
	depthDisabledStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR;
	depthDisabledStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
	depthDisabledStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
	depthDisabledStencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
	depthDisabledStencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR;
	depthDisabledStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
	depthDisabledStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;

	// Create the state using the device.
	result = mDevice->CreateDepthStencilState(&depthDisabledStencilDesc, &mDepthDisabledStencilState);
	if(FAILED(result))
	{
		return false;
	}

	// Set the depth stencil state.
	mContext->OMSetDepthStencilState(mDepthDisabledStencilState, 1);

	// Initialize the depth stencil view.
	ZeroMemory(&depthStencilViewDesc, sizeof(depthStencilViewDesc));

	// Set up the depth stencil view description.
	depthStencilViewDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
	depthStencilViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
	depthStencilViewDesc.Texture2D.MipSlice = 0;

	// Create the depth stencil view.
	result = mDevice->CreateDepthStencilView(mDepthStencilBuffer, &depthStencilViewDesc, &mDepthStencilView);
	if(FAILED(result))
	{
		return false;
	}

	// Bind the render target view and depth stencil view to the output render pipeline.
	mContext->OMSetRenderTargets(1, &mRenderTargetView, mDepthStencilView);

	
    return true;
}

/////////////////////////////////////////////////////////////////////////////////////////////
// 
//						SET RASTERIZER STATE
//
/////////////////////////////////////////////////////////////////////////////////////////////
bool D3DClass::SetRasterizerState()
{
	HRESULT result;
	D3D11_RASTERIZER_DESC rasterDesc;

	// Setup the raster description which will determine how and what polygons will be drawn.
	rasterDesc.AntialiasedLineEnable = false;
	rasterDesc.CullMode = D3D11_CULL_BACK;
	rasterDesc.DepthBias = 0;
	rasterDesc.DepthBiasClamp = 0.0f;
	rasterDesc.DepthClipEnable = true;
	rasterDesc.FillMode = D3D11_FILL_SOLID;
	rasterDesc.FrontCounterClockwise = false;
	rasterDesc.MultisampleEnable = false;
	rasterDesc.ScissorEnable = false;
	rasterDesc.SlopeScaledDepthBias = 0.0f;

	// Create the rasterizer state from the description we just filled out.
	result = mDevice->CreateRasterizerState(&rasterDesc, &mRasterizerState);
	if(FAILED(result))
	{
		return false;
	}

	// Now set the rasterizer state.
	mContext->RSSetState(mRasterizerState);

	return true;
}

/////////////////////////////////////////////////////////////////////////////////////////////
// 
//						SET VIEWPORT
//
/////////////////////////////////////////////////////////////////////////////////////////////
bool D3DClass::SetViewport(PlayerCount players)
{
	int ViewportWidth, ViewportHeight = 0;

	//Obtain screen dimensions from the OS Manager
	int screenDimensions[2] = { -1, -1 };
	Telegram telegram(0.0, mID, 0, Request::ScreenDimensions, screenDimensions);
	assert( g_pApp->HandleMessage(telegram) && "<WindowsMsg::RequestScreenDimensions> Unable to retrieve screen dimensions.");
	assert( (screenDimensions[0] != -1 && screenDimensions[1] != -1) && "<WindowsMsg::RequestScreenDimensions> Screen dimensions remain uninitialized");
	int screenWidth = screenDimensions[0];
	int screenHeight = screenDimensions[1];

	switch(players)
	{
	case ONE_PLAYER:
		ViewportWidth = screenWidth;
		ViewportHeight = screenHeight;
		break;
	case TWO_PLAYER:
		ViewportWidth = screenWidth / 2;
		ViewportHeight = screenHeight;
		break;
	case THREE_PLAYER:
		ViewportWidth = screenWidth / 2;
		ViewportHeight = screenHeight / 2;
		break;
	case FOUR_PLAYER:
		ViewportWidth = screenWidth / 2;
		ViewportHeight = screenHeight / 2;
		break;
	default:
		{
			assert(0 && L"Error: Undefined Number of Players.");
			return false;
		}
	}
	mViewport.TopLeftX = 0.0f;
	mViewport.TopLeftY = 0.0f;
	mViewport.Width = static_cast<float> (ViewportWidth);
	mViewport.Height = static_cast<float> (ViewportHeight);
	mViewport.MinDepth = 0.0f;
	mViewport.MaxDepth = 1.0f;
	
	mContext->RSSetViewports(1, &mViewport);

	return true;
}

/////////////////////////////////////////////////////////////////////////////////////////////
// 
//						CLEAR OLD SCREEN WITH PINK FOR DEBUGGING
//
/////////////////////////////////////////////////////////////////////////////////////////////
void D3DClass::ClearScreen()
{
	// Clear the back buffer.
	mContext->ClearRenderTargetView(mRenderTargetView, reinterpret_cast<const float*>(&Colors::Magenta) );
    
	// Clear the depth buffer.
	mContext->ClearDepthStencilView(mDepthStencilView, D3D11_CLEAR_DEPTH, 1.0f, 0);
}

/////////////////////////////////////////////////////////////////////////////////////////////
// 
//						PREPARE THE SCREEN FOR PRESENTATION
//
// Draw: Expects sourceRect to be in (-1,1) float coordinates
// DrawAtlased: Expects sourceRect to be in pixel coordinates, must convert
/////////////////////////////////////////////////////////////////////////////////////////////
void D3DClass::Draw(Rect sourceRect, Rect destRect, void * texture)
{
	NonAtlasedSpriteResourceBundle sprite;
	sprite.texture = (ID3D11ShaderResourceView*)texture;
	
	ID3D11Buffer * vertexBuffer;
	CreateQuadVertexBuffer(&vertexBuffer);
	UpdateQuadVertexBuffer(vertexBuffer, sourceRect, destRect);
	sprite.vertexBuffer = vertexBuffer;

	mNonAtlasedSpriteResources.push_back(sprite);
	
	
}

void D3DClass::DrawAtlased(Rect sourceRect, Rect destRect)
{
	// Convert source rect into (-1,1) float coordinates
	sourceRect.mUpperLeft.x.asFloat = (float)sourceRect.mUpperLeft.x.asInt / mAtlasWidth;
	sourceRect.mUpperLeft.y.asFloat = (float)sourceRect.mUpperLeft.y.asInt / mAtlasHeight;
	sourceRect.mWidth.asFloat = (float)sourceRect.mWidth.asInt / mAtlasWidth;
	sourceRect.mHeight.asFloat = (float)sourceRect.mHeight.asInt / mAtlasHeight;

	// Add vertices to vertex buffer
	SimpleVertex vertices[] =
    {
		
		{ XMFLOAT3( sourceRect.mUpperLeft.x.asFloat, sourceRect.mUpperLeft.y.asFloat, 1.0f ), 
							XMFLOAT2( destRect.mUpperLeft.x.asFloat, destRect.mUpperLeft.y.asFloat) },
		{ XMFLOAT3( sourceRect.mUpperLeft.x.asFloat + sourceRect.mWidth.asFloat, sourceRect.mUpperLeft.y.asFloat, 1.0f ), 
							XMFLOAT2( destRect.mUpperLeft.x.asFloat + destRect.mWidth.asFloat, destRect.mUpperLeft.y.asFloat) },
		{ XMFLOAT3( sourceRect.mUpperLeft.x.asFloat + sourceRect.mWidth.asFloat, sourceRect.mUpperLeft.y.asFloat + sourceRect.mHeight.asFloat, 1.0f ), 
							XMFLOAT2( destRect.mUpperLeft.x.asFloat + destRect.mWidth.asFloat, destRect.mUpperLeft.y.asFloat + destRect.mHeight.asFloat) },
		{ XMFLOAT3( sourceRect.mUpperLeft.x.asFloat, sourceRect.mUpperLeft.y.asFloat + sourceRect.mHeight.asFloat, 1.0f ), 
							XMFLOAT2( destRect.mUpperLeft.x.asFloat, destRect.mUpperLeft.y.asFloat + destRect.mHeight.asFloat) },
    };

	for(int i = 0; i < 4; ++i)
	{
		mAtlasedVertexBuffer.push_back( vertices[i]);
	}

	// Add indices to index buffer
	mAtlasedIndexBuffer.push_back( (mIndexedAtlasedSpriteCounter * 4) + 0);
	mAtlasedIndexBuffer.push_back( (mIndexedAtlasedSpriteCounter * 4) + 1);
	mAtlasedIndexBuffer.push_back( (mIndexedAtlasedSpriteCounter * 4) + 2);
	mAtlasedIndexBuffer.push_back( (mIndexedAtlasedSpriteCounter * 4) + 0);
	mAtlasedIndexBuffer.push_back( (mIndexedAtlasedSpriteCounter * 4) + 2);
	mAtlasedIndexBuffer.push_back( (mIndexedAtlasedSpriteCounter * 4) + 3);

	++mIndexedAtlasedSpriteCounter;
}

/////////////////////////////////////////////////////////////////////////////////////////////
// 
//						PRESENT SCREEN
//
/////////////////////////////////////////////////////////////////////////////////////////////
void D3DClass::Present()
{
	HRESULT hr;

	// Set constant D3D state
	mContext->IASetInputLayout( mVertexLayout );
	mContext->VSSetShader(mVertexShader, NULL, 0);
	mContext->PSSetShader(mPixelShader, NULL, 0);
	SetPrimitiveTopology();
	mContext->PSSetSamplers( 0, 1, &mSamplerLinear);

	// Draw atlased sprites
	ID3D11Buffer * vertexBuffer;
	ID3D11Buffer * indexBuffer;
	CreateVertexBuffer(&vertexBuffer, mAtlasedVertexBuffer);
	CreateIndexBuffer(&indexBuffer, mAtlasedIndexBuffer);
	SetBuffers(&vertexBuffer, &indexBuffer);
	mContext->PSSetShaderResources( 0, 1, &mCurrentMasterAtlas );
	mContext->DrawIndexed( mAtlasedIndexBuffer.size(), 0, 0 );
	vertexBuffer->Release();
	indexBuffer->Release();
	mAtlasedVertexBuffer.clear();
	mAtlasedIndexBuffer.clear();
	mIndexedAtlasedSpriteCounter = 0; // reset sprite counter for index buffer

	// Draw non-atlased sprites
	for(auto i = mNonAtlasedSpriteResources.begin(); i != mNonAtlasedSpriteResources.end(); ++i)
	{
		SetBuffers(&(i->vertexBuffer), &mStockIndexBuffer);
		mContext->PSSetShaderResources( 0, 1, &(i->texture) );
		mContext->DrawIndexed( 6, 0, 0 );
		i->vertexBuffer->Release();
	}

	// Present the back buffer to the screen since rendering is complete.
	if(mVSync)
	{
		// Lock to screen refresh rate.
		// OCCLUDED NEVER HAPPENING
		hr = mSwapChain->Present(1, 0);
		//if(hr == DXGI_STATUS_OCCLUDED) 
			//ApplicationCls->Pause();
	}
	else
	{
		// Present as fast as possible.
		// OCCLUDED NEVER HAPPENING
		hr = mSwapChain->Present(0, 0);
		//if(hr == DXGI_STATUS_OCCLUDED)
			//ApplicationCls->Pause();
	}

	return;
}

/////////////////////////////////////////////////////////////////////////////////////////////
// 
//						TURN Z BUFFER ON
//
/////////////////////////////////////////////////////////////////////////////////////////////
void D3DClass::TurnZBufferOn()
{
	mContext->OMSetDepthStencilState(mDepthEnabledStencilState, 1);
	return;
}

/////////////////////////////////////////////////////////////////////////////////////////////
// 
//						TURN Z BUFFER OFF
//
/////////////////////////////////////////////////////////////////////////////////////////////
void D3DClass::TurnZBufferOff()
{
	mContext->OMSetDepthStencilState(mDepthDisabledStencilState, 1);
	return;
}

/////////////////////////////////////////////////////////////////////////////////////////////
// 
//						GET ASPECT RATIO
//
/////////////////////////////////////////////////////////////////////////////////////////////
const float D3DClass::GetAspectRatio() const 
{ 
	//Obtain screen dimensions from the OS Manager
	int screenDimensions[2] = { -1, -1 };
	Telegram telegram(0.0, mID, 0, Request::ScreenDimensions, screenDimensions);
	assert( g_pApp->HandleMessage(telegram) && "<WindowsMsg::RequestScreenDimensions> Unable to retrieve screen dimensions.");
	assert( (screenDimensions[0] != -1 && screenDimensions[1] != -1) && "<WindowsMsg::RequestScreenDimensions> Screen dimensions remain uninitialized");
	int screenWidth = screenDimensions[0];
	int screenHeight = screenDimensions[1];

	return (float) screenWidth / screenHeight; 
}


/////////////////////////////////////////////////////////////////////////////////////////////
// 
//						GET VIDEO CARD INFO
//
/////////////////////////////////////////////////////////////////////////////////////////////
void D3DClass::GetVideoCardInfo(char* cardName, int& memory) const
{
	strcpy_s(cardName, 128, mVideoCardDescription);
	memory = mVRam;
	return;
}

/////////////////////////////////////////////////////////////////////////////////////////////
// 
//						GETTERS
//
/////////////////////////////////////////////////////////////////////////////////////////////
void D3DClass::GetProjectionMatrix(XMMATRIX& projectionMatrix)
{
	projectionMatrix = XMLoadFloat4x4(&mProj);
	return;
}


void D3DClass::GetIWorldMatrix(XMMATRIX& worldMatrix)
{
	worldMatrix = XMLoadFloat4x4(&mIWorld);
	return;
}


void D3DClass::GetOrthoMatrix(XMMATRIX& orthoMatrix)
{
	orthoMatrix = XMLoadFloat4x4(&mOrtho);
	return;
}

/////////////////////////////////////////////////////////////////////////////////////////////
// 
//	Disallow Alt-Enter detect. Custom Define.
//
/////////////////////////////////////////////////////////////////////////////////////////////
bool D3DClass::MakeWindowAssociation()
{
	HWND hwnd = 0;
	Telegram telegram(0.0, mID, 0, Request::WindowHandle, &hwnd);
	assert( g_pApp->HandleMessage(telegram) && "<WindowsMsg::WindowHandle> Unable to obtain window handle.");
	assert( (hwnd != 0 ) && "<WindowsMsg::RequestWindowHandle> Window handle remain uninitialized");
	
	//COM queries to get at the correct IDXGIFactory instance used to create the device
	//Query Interface
	IDXGIDevice * dxgiDevice = 0;
	mDevice->QueryInterface(__uuidof(IDXGIDevice), (void**) &dxgiDevice);
	if(!dxgiDevice)
		return false;

	//Query Adapter
	IDXGIAdapter * dxgiAdapter = 0;
	dxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void**) &dxgiAdapter);
	if(!dxgiAdapter)
		return false;

	//Finally get the IDXGIFactory interface.
	IDXGIFactory * dxgiFactory = 0;
	dxgiAdapter->GetParent(__uuidof(IDXGIFactory), (void**) &dxgiFactory);
	if(!dxgiFactory)
		return false;
	//Disallow Automatic Alt-Enter detect, custom define.
	HR(dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_WINDOW_CHANGES) );

	//Release our acquired COM interfaces (because we are done with them).
	ReleaseCOM(dxgiDevice);
	ReleaseCOM(dxgiAdapter);
	ReleaseCOM(dxgiFactory);

	return true;
}

/////////////////////////////////////////////////////////////////////////////////////////////
// 
//	Load all shaders from pre-compiled .cso files in Assets				
//
/////////////////////////////////////////////////////////////////////////////////////////////

bool D3DClass::LoadCompiledShadersFromFile()
{
	HRESULT hr = 0;

	//Load compiled shaders into memory
	LoadShaderFromFile(VS_NAME, &mVSBlob );
	LoadShaderFromFile(PS_NAME, &mPSBlob );

	hr = mDevice->CreateVertexShader(mVSBlob->GetBufferPointer(), mVSBlob->GetBufferSize(), 0, &mVertexShader);
	hr = mDevice->CreatePixelShader(mPSBlob->GetBufferPointer(), mPSBlob->GetBufferSize(), 0, &mPixelShader);

	if(!CreateLayout(mVSBlob->GetBufferPointer(), mVSBlob->GetBufferSize()) )
		return false;


	//ReleaseCOM(mVSBlob);
	//ReleaseCOM(mPSBlob);
	return true;

}

bool D3DClass::LoadShaderFromFile(const wchar_t * filename, ID3DBlob ** blob)
{
	HRESULT hr = 0;
	std::wstring fullpath(Util::AppendAssetsDirectory(filename) );
	//MessageBox(WindowsCls->GetHwnd(), fullpath.c_str(), 0, 0); 
	
	
	std::ifstream fin(fullpath.c_str(), std::ios::binary);
	assert(fin);
	
	fin.seekg(0, std::ios_base::end);
	
	int size = (int)fin.tellg();
	fin.seekg(0, std::ios_base::beg);

	hr = D3DCreateBlob(size, blob);

	fin.read((char*) (*blob)->GetBufferPointer(), (*blob)->GetBufferSize());
	fin.close();

	return true;
}


/////////////////////////////////////////////////////////////////////////////////////////////
// 
//			Create the sampler state
//
/////////////////////////////////////////////////////////////////////////////////////////////

bool D3DClass::CreateSamplerState()
{
    D3D11_SAMPLER_DESC sampDesc;
	HRESULT hr = 0;

    ZeroMemory( &sampDesc, sizeof(sampDesc) );
    sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
    sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
    sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
    sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
    sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
    sampDesc.MinLOD = 0;
    sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
	hr = mDevice->CreateSamplerState( &sampDesc, &mSamplerLinear );
    if( FAILED( hr ) )
        return false;

	return true;
}


/////////////////////////////////////////////////////////////////////////////////////////////
// 
//			Create Input Layout
//
/////////////////////////////////////////////////////////////////////////////////////////////

bool D3DClass::CreateLayout(const void * vertexBuffer, int size)
{
	HRESULT hr = 0;

	// Define the input layout
    D3D11_INPUT_ELEMENT_DESC layout[] =
    {
        { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "TEXTURE", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    };
	UINT numElements = ARRAYSIZE( layout );

	// Create the input layout
	hr = mDevice->CreateInputLayout( layout, numElements, vertexBuffer,
                                          size, &mVertexLayout );
	if( FAILED( hr ) )
        return false;

    // Set the input layout
	mContext->IASetInputLayout( mVertexLayout );

	return true;
}


void D3DClass::SetPrimitiveTopology()
{
	// Set primitive topology
    mContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
}

/////////////////////////////////////////////////////////////////////////////////////////////
// 
//			Updates the vertex buffers stored in each bitmap.
//
/////////////////////////////////////////////////////////////////////////////////////////////
bool D3DClass::UpdateQuadVertexBuffer(void * vertexBuffer, const Rect &sourceRect, const Rect &destRect)
{
	D3D11_MAPPED_SUBRESOURCE mappedResource;
	SimpleVertex * verticesPtr;
	HRESULT result;

	SimpleVertex vertices[] =
    {
		
		{ XMFLOAT3( sourceRect.mUpperLeft.x.asFloat, sourceRect.mUpperLeft.y.asFloat, 1.0f ), 
							XMFLOAT2( destRect.mUpperLeft.x.asFloat, destRect.mUpperLeft.y.asFloat) },
		{ XMFLOAT3( sourceRect.mUpperLeft.x.asFloat + sourceRect.mWidth.asFloat, sourceRect.mUpperLeft.y.asFloat, 1.0f ), 
							XMFLOAT2( destRect.mUpperLeft.x.asFloat + destRect.mWidth.asFloat, destRect.mUpperLeft.y.asFloat) },
		{ XMFLOAT3( sourceRect.mUpperLeft.x.asFloat + sourceRect.mWidth.asFloat, sourceRect.mUpperLeft.y.asFloat + sourceRect.mHeight.asFloat, 1.0f ), 
							XMFLOAT2( destRect.mUpperLeft.x.asFloat + destRect.mWidth.asFloat, destRect.mUpperLeft.y.asFloat + destRect.mHeight.asFloat) },
		{ XMFLOAT3( sourceRect.mUpperLeft.x.asFloat, sourceRect.mUpperLeft.y.asFloat + sourceRect.mHeight.asFloat, 1.0f ), 
							XMFLOAT2( destRect.mUpperLeft.x.asFloat, destRect.mUpperLeft.y.asFloat + destRect.mHeight.asFloat) },
    };


	// Lock the vertex buffer so it can be written to.
	result = mContext->Map( (ID3D11Resource*) vertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
	if(FAILED(result))
	{
		return false;
	}

	// Get a pointer to the data in the vertex buffer.
	verticesPtr = (SimpleVertex*) mappedResource.pData;

	// Copy the data into the vertex buffer.
	memcpy(verticesPtr, (void*)vertices, (sizeof(SimpleVertex) * QUAD_VERTEX_COUNT));

	// Unlock the vertex buffer.
	mContext->Unmap((ID3D11Resource*) vertexBuffer, 0);


	return true;
}

/////////////////////////////////////////////////////////////////////////////////////////////
// 
//			Used to wrap D3DX create texture from file functions
//
/////////////////////////////////////////////////////////////////////////////////////////////
bool D3DClass::CreateTextureFromFile(std::wstring bitmapPath, void * const * texture)
{
	
	HRESULT hr = D3DX11CreateShaderResourceViewFromFile( mDevice, bitmapPath.c_str(), NULL, NULL, (ID3D11ShaderResourceView **) texture, NULL );
	
	if(FAILED(hr))
		return false;
	else
		return true;
}


/////////////////////////////////////////////////////////////////////////////////////////////
// 
//			Simple Wrapper Functions
//
/////////////////////////////////////////////////////////////////////////////////////////////
void D3DClass::ReleaseResource( void ** resource )
{
	if(!*resource) return;

	IUnknown * comResource = static_cast<IUnknown*>(*resource);
	ReleaseCOM( comResource );
}

HRESULT D3DClass::CreateQuadVertexBuffer(ID3D11Buffer ** buffer)
{
	// Create the vertex array.
	SimpleVertex vertices[] =
    {
		
		{ XMFLOAT3( -1.0f, 1.0f, 1.0f ), XMFLOAT2( 0.0f, 0.0f) },
		{ XMFLOAT3( 1.0f, 1.0f, 1.0f ), XMFLOAT2( 1.0f, 0.0f) },
		{ XMFLOAT3( 1.0f, -1.0f, 1.0f ), XMFLOAT2( 1.0f, 1.0f) },
		{ XMFLOAT3( -1.0f, -1.0f, 1.0f ), XMFLOAT2( 0.0f, 1.0f) },
    };

	// Set up the description of the static vertex buffer.
    D3D11_BUFFER_DESC vertexBufferDesc;
	vertexBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
    vertexBufferDesc.ByteWidth = sizeof(SimpleVertex) * QUAD_VERTEX_COUNT;
    vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
    vertexBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
    vertexBufferDesc.MiscFlags = 0;
	vertexBufferDesc.StructureByteStride = 0;

	// Give the subresource structure a pointer to the vertex data.
    D3D11_SUBRESOURCE_DATA vertexData;
	vertexData.pSysMem = vertices;
	vertexData.SysMemPitch = 0;
	vertexData.SysMemSlicePitch = 0;

	HRESULT hr = mDevice->CreateBuffer(&vertexBufferDesc, &vertexData, buffer);

	return hr;
}

HRESULT D3DClass::CreateVertexBuffer(ID3D11Buffer ** buffer, const std::vector<SimpleVertex> &vertices)
{
	
	// Set up the description of the static vertex buffer.
    D3D11_BUFFER_DESC vertexBufferDesc;
	vertexBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
    vertexBufferDesc.ByteWidth = sizeof(SimpleVertex) * vertices.size();
    vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
    vertexBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
    vertexBufferDesc.MiscFlags = 0;
	vertexBufferDesc.StructureByteStride = 0;

	// Give the subresource structure a pointer to the vertex data.
    D3D11_SUBRESOURCE_DATA vertexData;
	vertexData.pSysMem = &vertices[0];
	vertexData.SysMemPitch = 0;
	vertexData.SysMemSlicePitch = 0;

	HRESULT hr = mDevice->CreateBuffer(&vertexBufferDesc, &vertexData, buffer);

	return hr;
}

HRESULT D3DClass::CreateQuadIndexBuffer(ID3D11Buffer ** buffer)
{
	D3D11_BUFFER_DESC indexBufferDesc;
	D3D11_SUBRESOURCE_DATA indexData;
	HRESULT result;

	uint32_t indices[] =
    {
        0,1,2,
        0,2,3,
    };

	// Set up the description of the static index buffer.
    indexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
    indexBufferDesc.ByteWidth = sizeof(unsigned long) * QUAD_INDEX_COUNT;
    indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
    indexBufferDesc.CPUAccessFlags = 0;
    indexBufferDesc.MiscFlags = 0;
	indexBufferDesc.StructureByteStride = 0;

	// Give the subresource structure a pointer to the index data.
    indexData.pSysMem = indices;
	indexData.SysMemPitch = 0;
	indexData.SysMemSlicePitch = 0;

	// Create the index buffer.
	result = mDevice->CreateBuffer(&indexBufferDesc, &indexData, buffer);

	return result;
}

HRESULT D3DClass::CreateIndexBuffer(ID3D11Buffer ** buffer, const std::vector<uint32_t> &indices)
{
	D3D11_BUFFER_DESC indexBufferDesc;
	D3D11_SUBRESOURCE_DATA indexData;
	HRESULT result;

	// Set up the description of the static index buffer.
    indexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
    indexBufferDesc.ByteWidth = sizeof(unsigned long) * indices.size();
    indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
    indexBufferDesc.CPUAccessFlags = 0;
    indexBufferDesc.MiscFlags = 0;
	indexBufferDesc.StructureByteStride = 0;

	// Give the subresource structure a pointer to the index data.
    indexData.pSysMem = &indices[0];
	indexData.SysMemPitch = 0;
	indexData.SysMemSlicePitch = 0;

	// Create the index buffer.
	result = mDevice->CreateBuffer(&indexBufferDesc, &indexData, buffer);

	return result;
}

void D3DClass::SetBuffers(ID3D11Buffer ** vertexBuffer, ID3D11Buffer ** indexBuffer)
{
	// Set vertex buffer stride and offset.
	unsigned int stride = sizeof(SimpleVertex); 
	unsigned int offset = 0;
	
	// Set the vertex buffer to active in the input assembler so it can be rendered.
	mContext->IASetVertexBuffers(0, 1, vertexBuffer, &stride, &offset);

    // Set the index buffer to active in the input assembler so it can be rendered.
	mContext->IASetIndexBuffer((*indexBuffer), DXGI_FORMAT_R32_UINT, 0);
}


